package zdream.control.region;

import java.util.*;

import zdream.utils.math.IntRectangle;
import zdream.utils.math.Point2d;
import zdream.utils.math.Rectangle;

import static org.junit.Assert.*;
import static zdream.control.region.TerrainConstant.*;

/**
 * @author Zdream
 * @date 2023-12-25
 * @since 0.0.1
 */
public class SimpleRegionBuilder extends RegionBuilder {
	public SimpleRegionBuilder(String name) {
		super(name);
	}

	/* **********
	 * 覆盖方法 *
	 ********** */

	@Override
	public SimpleRegionBuilder withRoomPositions(IntRectangle[] rectList) {
		super.withRoomPositions(rectList);
		return this;
	}

	@Override
	public SimpleRegionBuilder withFieldsSpawnAt(Rectangle positionInRegion, String key) {
		super.withFieldsSpawnAt(positionInRegion, key);
		return this;
	}

	@Override
	public SimpleRegionBuilder withFieldsSpawnAt(float x, float y, float width, float height, String key) {
		super.withFieldsSpawnAt(x, y, width, height, key);
		return this;
	}

	@Override
	public SimpleRegionBuilder defineField(String fieldKey, ItemSpec param) {
		super.defineField(fieldKey, param);
		return this;
	}

	public SimpleRegionBuilder defineFoe(String foeKey, String foeName) {
		return defineFoe(foeKey, new ItemSpec(foeName));
	}

	@Override
	public SimpleRegionBuilder defineFoe(String foeKey, ItemSpec param) {
		super.defineFoe(foeKey, param);
		return this;
	}

	@Override
	public SimpleRegionBuilder withFoeSpawnAt(float x, float y, String foeKey) {
		super.withFoeSpawnAt(x, y, foeKey);
		return this;
	}

	@Override
	public SimpleRegionBuilder withFoeSpawnAt(float x, float y, String foeKey, String pointName) {
		super.withFoeSpawnAt(x, y, foeKey, pointName);
		return this;
	}

	@Override
	public SimpleRegionBuilder withStartPoint(float xInRegion, float yInRegion) {
		super.withStartPoint(xInRegion, yInRegion);
		return this;
	}

	@Override
	public SimpleRegionBuilder withSavePoint(float xInRegion, float yInRegion, String pointName) {
		super.withSavePoint(xInRegion, yInRegion, pointName);
		return this;
	}

	/* **********
	 *   地形   *
	 ********** */
	final Map<Character, List<Point2d>> points = new HashMap<>();
	final Map<Character, Byte> terrainMap = new HashMap<>();

	{
		terrainMap.put(' ', TERRAIN_EMPTY);
		terrainMap.put('#', TERRAIN_SOLID);
		terrainMap.put('~', TERRAIN_WATER_TOP_SURFACE);
		terrainMap.put('-', TERRAIN_WATER);
		terrainMap.put('=', TERRAIN_WATER_BOTTOM_SURFACE);
		terrainMap.put('*', TERRAIN_STAB_BALL);
		terrainMap.put('^', TERRAIN_STAB_UP);
		terrainMap.put('+', TERRAIN_LADDER);
	}

	public SimpleRegionBuilder withRoomPositions(String text) {
		parseRoomPositions(text);
		return this;
	}

	public SimpleRoomBuilder withRoom(int roomId) {
		return new SimpleRoomBuilder(this, region.findRoom(roomId));
	}

	private void parseRoomPositions(String text) {
		if (region.rooms != null) {
			throw new IllegalStateException("room 已经被设置了");
		}

		final String[] lines = text.split("\n"); // 0,0 坐标在左下
		int maxLength = Arrays.stream(lines).mapToInt(String::length).max().orElse(0);
		if (maxLength == 0) {
			return;
		}

		IntRectangle[] rects = new IntRectangle[10];

		for (int i = 0; i < lines.length; i++) {
			int y = lines.length - i - 1;
			char[] line = lines[i].toCharArray();

			for (int x = 0; x < line.length; x++) {
				char c = line[x];
				if (c == ' ') {
					continue;
				}

				int id;
				if (Character.isDigit(c)) {
					id = Character.digit(c, 10);
				} else {
					throw new IllegalArgumentException("Invalid room text: " + text);
				}

				if (rects[id] == null) {
					rects[id] = new IntRectangle(x, y, 1, 1);
					continue;
				}

				IntRectangle old = rects[id];
				int fromX = Math.min(x, old.x);
				int toX = Math.max(x, old.x);
				int fromY = Math.min(y, old.y);
				int toY = Math.max(y, old.y);

				for (int xx = fromX; xx <= toX; xx++) {
					for (int yy = fromY; yy <= toY; yy++) {
						try {
							char cc = lines[yy].charAt(xx);
							if (cc != c) {
								throw new IllegalArgumentException("Invalid room text: " + text);
							}
						} catch (ArrayIndexOutOfBoundsException e) {
							throw new IllegalArgumentException("Invalid room text: " + text);
						}
					}
				}

				old.withX(fromX).withY(fromY).withWidth(toX - fromX).withHeight(toY - fromY);
			}
		}

		for (final IntRectangle rect : rects) {
			if (rect == null) {
				continue;
			}
			rect.x = rect.x * Region.BLOCK_WIDTH;
			rect.y = rect.y * Region.BLOCK_HEIGHT;
			rect.width = rect.width * Region.BLOCK_WIDTH;
			rect.height = rect.height * Region.BLOCK_HEIGHT;
		}

		withRoomPositions(rects);
	}

	public SimpleRegionBuilder defineTerrain(char ch, byte terrain) {
		assertFalse("该字母已经被定义了", terrainMap.containsKey(ch));
		terrainMap.put(ch, terrain);
		points.put(ch, new ArrayList<>());
		return this;
	}

	public SimpleRegionBuilder withFoeSpawnAt(char c, String foeKey) {
		return withFoeSpawnAt(c, foeKey, 0.5f, 0, Character.toString(c));
	}

	public SimpleRegionBuilder withFoeSpawnAt(char c, String foeKey, float offsetX, float offsetY) {
		return withFoeSpawnAt(c, foeKey, offsetX, offsetY, Character.toString(c));
	}

	public SimpleRegionBuilder withFoeSpawnAt(char c, String foeKey, float offsetX, float offsetY, String pointName) {
		List<Point2d> point2ds = points.get(c);
		if (point2ds == null) {
			throw new RuntimeException("你还没有定义字母 " + c + " 的地形");
		}

		for (Point2d p : point2ds) {
			super.withFoeSpawnAt(p.x + offsetX, p.y + offsetY, foeKey, pointName);
		}
		return this;
	}

	public SimpleRegionBuilder withStartPoint(char c) {
		List<Point2d> point2ds = points.get(c);
		if (point2ds == null) {
			throw new RuntimeException("你还没有定义字母 " + c + " 的地形");
		}

		assertEquals("你只能定义一个 start point", 1, point2ds.size());
		Point2d point2d = point2ds.get(0);
		return withStartPoint(point2d.x + 0.5f, point2d.y);
	}

	public SimpleRegionBuilder withSavePoint(char c) {
		List<Point2d> point2ds = points.get(c);
		if (point2ds == null) {
			throw new RuntimeException("你还没有定义字母 " + c + " 的地形");
		}

		int index = 0;
		for (Point2d p : point2ds) {
			withSavePoint(p.x + 0.5f, p.y, String.format("%s-%d", c, index++));
		}
		return this;
	}
}
